#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "crypto/md5tool.h"
#include "crypto/md5.h"
#include "crypto/tool.h"
#include "crypto/types.h"

static bool md5ValueCompare(MD5_value *res, MD5_value *dst)
{
    return res->value[0] == dst->value[0] &&
           res->value[1] == dst->value[1] &&
           res->value[2] == dst->value[2] &&
           res->value[3] == dst->value[3];
}

static MD5_value *md5(SAFE_array *formatData)
{
    int loopNumber = formatData->size / MD5_BLOCK_SIZE;
    MD5_value *val = (MD5_value *)malloc(sizeof(MD5_value));
    uint *dataPtr = val->value;
    byte *resPtr = formatData->data;
    uint A, B, C, D;
    dataPtr[0] = MD5_CONST_A;
    dataPtr[1] = MD5_CONST_B;
    dataPtr[2] = MD5_CONST_C;
    dataPtr[3] = MD5_CONST_D;

    A = dataPtr[0];
    B = dataPtr[1];
    C = dataPtr[2];
    D = dataPtr[3];

    for (int i = 0; i < loopNumber; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            hexLoop(j, dataPtr, (int *)(resPtr + i * MD5_BLOCK_SIZE));
        }
        A = (dataPtr[0] += A);
        B = (dataPtr[1] += B);
        C = (dataPtr[2] += C);
        D = (dataPtr[3] += D);
    }
    LTOB(dataPtr);
    LTOB(dataPtr + 1);
    LTOB(dataPtr + 2);
    LTOB(dataPtr + 3);
    free(formatData);
    return val;
}

MD5_value *md5sum(byte *data, int len)
{
    SAFE_array *formatData = preDeal(data, len);
    return md5(formatData);
}

bool md5check(byte *data, int len)
{
    MD5_value md5CheckCode;
    memcpy(&md5CheckCode, data + (len - 16), 16);
    SAFE_array *formatData = preDeal(data, len - 16);
    MD5_value *md5CheckResult = md5(formatData);
    return md5ValueCompare(&md5CheckCode, md5CheckResult);
}